"""
米游社账号相关操作 API 请求模块。
"""

import uuid
import random
from copy import deepcopy
from string import digits, ascii_letters
from typing import Dict, Union, Optional, cast

from aiohttp import ClientSession

from .tools import (
    random_hex,
    mys_version,
    random_text,
    get_web_ds_token,
    generate_passport_ds,
)
from .models import (
    AuthKeyInfo,
    QrCodeStatus,
    GameTokenInfo,
    CookieTokenInfo,
    LoginTicketInfo,
)
from .pass_request import PassMysApi


class AccountMysApi(PassMysApi):
    """
    账号相关请求
    """

    async def get_cookie_token(self, token: str, uid: str) -> Union[CookieTokenInfo, int]:
        data = await self._mys_request(
            self.MAPI["GET_COOKIE_TOKEN_BY_GAME_TOKEN"],
            "GET",
            params={
                "game_token": token,
                "account_id": uid,
            },
        )
        if isinstance(data, Dict):
            data = cast(CookieTokenInfo, data["data"])
        return data

    async def create_qrcode_url(self) -> Union[Dict, int]:
        device_id: str = "".join(random.choices(ascii_letters + digits, k=64))
        app_id: str = "2"
        data = await self._mys_request(
            self.MAPI["CREATE_QRCODE"],
            "POST",
            header={},
            data={"app_id": app_id, "device": device_id},
        )
        if isinstance(data, Dict):
            url: str = data["data"]["url"]
            ticket = url.split("ticket=")[1]
            return {
                "app_id": app_id,
                "ticket": ticket,
                "device": device_id,
                "url": url,
            }
        return data

    async def check_qrcode(self, app_id: str, ticket: str, device: str) -> Union[QrCodeStatus, int]:
        data = await self._mys_request(
            self.MAPI["CHECK_QRCODE"],
            "POST",
            data={
                "app_id": app_id,
                "ticket": ticket,
                "device": device,
            },
        )
        if isinstance(data, Dict):
            data = cast(QrCodeStatus, data["data"])
        return data

    async def get_cookie_token_by_game_token(self, token: str, uid: str) -> Union[CookieTokenInfo, int]:
        data = await self._mys_request(
            self.MAPI["GET_COOKIE_TOKEN_BY_GAME_TOKEN"],
            "GET",
            params={
                "game_token": token,
                "account_id": uid,
            },
        )
        if isinstance(data, Dict):
            data = cast(CookieTokenInfo, data["data"])
        return data

    async def get_cookie_token_by_stoken(
        self, stoken: str, mys_id: str, full_sk: Optional[str] = None
    ) -> Union[CookieTokenInfo, int]:
        HEADER = deepcopy(self._HEADER)
        if full_sk:
            HEADER["Cookie"] = full_sk
        else:
            HEADER["Cookie"] = f"stuid={mys_id};stoken={stoken}"
        data = await self._mys_request(
            url=self.MAPI["GET_COOKIE_TOKEN_URL"],
            method="GET",
            header=HEADER,
            params={
                "stoken": stoken,
                "uid": mys_id,
            },
        )
        if isinstance(data, Dict):
            data = cast(CookieTokenInfo, data["data"])
        return data

    async def get_stoken_by_login_ticket(self, lt: str, mys_id: str) -> Union[LoginTicketInfo, int]:
        data = await self._mys_request(
            url=self.MAPI["GET_STOKEN_URL"],
            method="GET",
            header=self._HEADER,
            params={
                "login_ticket": lt,
                "token_types": "3",
                "uid": mys_id,
            },
        )
        if isinstance(data, int):
            data = await self._mys_request(
                url=self.MAPI["GET_STOKEN_URL_OS"],
                method="GET",
                header=self._HEADER,
                params={
                    "login_ticket": lt,
                    "token_types": "3",
                    "uid": mys_id,
                },
            )
        if isinstance(data, Dict):
            data = cast(LoginTicketInfo, data["data"])
        return data

    async def get_stoken_by_game_token(self, account_id: int, game_token: str) -> Union[GameTokenInfo, int]:
        _data = {
            "account_id": account_id,
            "game_token": game_token,
        }
        data = await self._mys_request(
            self.MAPI["GET_STOKEN"],
            "POST",
            {
                "x-rpc-app_version": "2.41.0",
                "DS": generate_passport_ds(b=_data),
                "x-rpc-aigis": "",
                "Content-Type": "application/json",
                "Accept": "application/json",
                "x-rpc-game_biz": "bbs_cn",
                "x-rpc-sys_version": "11",
                "x-rpc-device_id": uuid.uuid4().hex,
                "x-rpc-device_fp": "".join(random.choices(ascii_letters + digits, k=13)),
                "x-rpc-device_name": "GenshinUid_login_device_lulu",
                "x-rpc-device_model": "GenshinUid_login_device_lulu",
                "x-rpc-app_id": "bll8iq97cem8",
                "x-rpc-client_type": "2",
                "User-Agent": "okhttp/4.8.0",
            },
            data=_data,
        )
        if isinstance(data, Dict):
            data = cast(GameTokenInfo, data["data"])
        return data

    async def get_authkey_by_cookie(
        self, uid: str, game_biz: str = "hk4e_cn", server_id: str = ""
    ) -> Union[AuthKeyInfo, int]:
        if not server_id:
            server_id = self.RECOGNIZE_SERVER.get(str(uid)[0], "cn_gf01")
        HEADER = deepcopy(self._HEADER)
        stoken = await self.get_stoken(uid)
        if stoken is None:
            return -51
        HEADER["Cookie"] = stoken
        HEADER["DS"] = get_web_ds_token(True)
        HEADER["User-Agent"] = "okhttp/4.8.0"
        HEADER["x-rpc-app_version"] = mys_version
        HEADER["x-rpc-sys_version"] = "12"
        HEADER["x-rpc-client_type"] = "5"
        HEADER["x-rpc-channel"] = "mihoyo"
        HEADER["x-rpc-device_id"] = random_hex(32)
        HEADER["x-rpc-device_name"] = random_text(random.randint(1, 10))
        HEADER["x-rpc-device_model"] = "Mi 10"
        HEADER["Referer"] = "https://app.mihoyo.com"
        HEADER["Host"] = "api-takumi.mihoyo.com"
        data = await self._mys_request(
            url=self.MAPI["GET_AUTHKEY_URL"],
            method="POST",
            header=HEADER,
            data={
                "auth_appid": "webview_gacha",
                "game_biz": game_biz,
                "game_uid": uid,
                "region": server_id,
            },
        )
        if isinstance(data, Dict):
            data = cast(AuthKeyInfo, data["data"])
        return data

    async def get_hk4e_token(self, uid: str):
        # 获取e_hk4e_token
        server_id = self.RECOGNIZE_SERVER.get(uid[0])
        header = {
            "Cookie": await self.get_ck(uid, "OWNER", None),
            "Content-Type": "application/json;charset=UTF-8",
            "Referer": "https://webstatic.mihoyo.com/",
            "Origin": "https://webstatic.mihoyo.com",
        }
        use_proxy = False
        data = {
            "game_biz": "hk4e_cn",
            "lang": "zh-cn",
            "uid": f"{uid}",
            "region": f"{server_id}",
        }
        if int(str(uid)[0]) < 6:
            url = self.MAPI["HK4E_LOGIN_URL"]
        else:
            url = self.MAPI["HK4E_LOGIN_URL_OS"]
            data["game_biz"] = "hk4e_global"
            use_proxy = True

        if use_proxy and self.Gproxy:
            proxy = self.Gproxy
        elif self.Nproxy and not use_proxy:
            proxy = self.Nproxy
        else:
            proxy = None

        async with ClientSession() as client:
            async with client.request(
                method="POST",
                url=url,
                headers=header,
                json=data,
                proxy=proxy,
                timeout=300,
            ) as resp:
                raw_data = await resp.json()
                if "retcode" in raw_data and raw_data["retcode"] == 0:
                    _k = resp.cookies["e_hk4e_token"].key
                    _v = resp.cookies["e_hk4e_token"].value
                    ck = f"{_k}={_v}"
                    return ck
                else:
                    return None
